﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Web;
using System.Web.SessionState;

using SSN.Utilities.Database;
using SSN.Objects;
using SSN.Security;
using SSN.Utilities.Cache;

using SSN.BusinessFramework.Reps;
using SSN.DotNet;
using SSN.Data.Database;
using System.Data;
using SSN.BusinessFramework.CRM;
using SSN.BusinessFramework;

namespace SSN.WebFramework
{
    /// <summary>
    /// Manages various pieces of information related to the current user logged in.
    /// </summary>
    public class UserManager
    {
        private SSNSecurityContext _ctx;
        internal static KeyValueCache<string, FocalwebUser> _uCache = new KeyValueCache<string, FocalwebUser>(new TimeSpan(0, 1, 0));
        internal static KeyValueCache<string, List<LinkedRep>> _lrCache = new KeyValueCache<string, List<LinkedRep>>(new TimeSpan(0, 30, 0));
	   internal static KeyValueCache<string,List<Contact>> _linkContactsCache=new KeyValueCache<string,List<Contact>>(new TimeSpan(0,30,0));

        public UserManager(SSNSecurityContext context)
        {
            _ctx = context;
        }

        /// <summary>
        /// When a user logs out, purge their cache information.
        /// </summary>
        /// <param name="context">Security context</param>
        internal static void PurgeUser(SSNSecurityContext context)
        {
            _uCache.DecacheItem(context.userid);
            _lrCache.DecacheItem(context.userid);
            _linkContactsCache.DecacheItem(context.userid);
        }

        /// <summary>
        /// Used only for internal caching of users.
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        internal static FocalwebUser getUser(string userID)
        {
            if (String.IsNullOrEmpty(userID))
            {
                return null;
            }

            if (_uCache[userID] == null)
            {
                var cu = new FWCachedUser();
                if (cu.Load(userID))
                {
                    _uCache.CacheItem(userID, cu);
                }
            }
            return _uCache[userID];
        }



        /// <summary>
        /// Returns a list of reps linked to the user.
        /// </summary>
        public List<LinkedRep> LinkedReps
        {
            get
            {
                if (_lrCache[_ctx.userid] == null)
                {
                    List<LinkedRep> reps = new List<LinkedRep>();
                    List<UserRep> userReps = getUser(_ctx.userid).Representatives;
                    foreach (UserRep rep in userReps)
                    {
                        reps.Add(new LinkedRep(rep.repno, rep.SecurityLevel.ToString().ToEnum<LinkedRepType>(), RepManager.GetRepByNumber(rep.repno).FullName));
                    }

                    _lrCache.CacheItem(_ctx.userid, reps);
                }

                return _lrCache[_ctx.userid];
            }
        }

        /// <summary>
        /// Returns a list of rep numbers linked to the user.
        /// </summary>
        public List<string> LinkedRepNumbers
        {
            get
            {
                return (from r in LinkedReps select r.RepNumber).ToList();
            }
        }

	    /// <summary>
	    /// A list of contacts linked to the current user.
	    /// </summary>
	   public List<Contact> LinkedContacts {
		   get {
			   if(_linkContactsCache[_ctx.userid]==null) {
				   ContactSearch search=new ContactSearch(_ctx);
				   search.Link=_ctx.userid;
				   search.Type=ContactTypeCodes.User.Key;
				   List<Contact> list=search.DoSearch();
				   search.Link=LinkedReps.Select(rep => rep.RepNumber).ToDelimitedString(" ");
				   search.Type=ContactTypeCodes.Rep.Key;
				   list.AddRange(search.DoSearch());
				   _linkContactsCache.CacheItem(_ctx.userid,list);
			   }
			   return _linkContactsCache[_ctx.userid];
		   }
	   }

	    /// <summary>
	    /// The contact object corresponding to this user.
	    /// </summary>
	   public Contact Contact { get { return LinkedContacts.Where(contact => contact.Type==ContactTypeCodes.User.Key&&contact.Link==_ctx.userid).FirstOrDefault(); } }

	    /// <summary>
	    /// Finds the contact for the rep linked to this user with the given rep number.
	    /// </summary>
	    /// <param name="repNumber">The rep number of the rep to look for.</param>
	    /// <returns>The contact for the rep with given rep number, or null if it is not linked to this user.</returns>
	   public Contact GetRepContact(string repNumber) {
		   return LinkedContacts.Where(contact => contact.Type==ContactTypeCodes.Rep.Key&&contact.Link.Equals(repNumber)).FirstOrDefault();
	   }
    }
}
